<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .list-wrap {
            position: relative;
            overflow-y: scroll;
            width: 200px;
            margin: 100px auto;
            box-sizing: border-box;
            border: solid 1px red;
        }

        .list {
            position: absolute;
            top: 0;
            left: 0;
        }

        .list li {
            border: solid 1px blue;
            line-height: 30px;
        }
    </style>
</head>

<body>
    <!-- 
    虚拟列表的基本实现思路:
        用vue的for循环渲染列表，自己手动加一个滚动条，然后通过监听scroll，
        算出应该显示到第几个，通过计算属性截取显示的数据
    -->
    <ul id="app">
        <div class="list-wrap" ref="listWrap" @scroll="scrollListener">
            <div class="scroll-bar" ref="scrollBar"></div>
            <ul class="list" ref="list">
                <li v-for="val in showList">{{val}}</li>
            </ul>
        </div>
    </ul>
    <script src="../gshop-client/node_modules/vue/dist/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    list: [], //超长的显示数据
                    itemHeight: 30, //每一列的高度
                    showNum: 10, //显示几条数据
                    start: 0, //滚动过程显示的开始索引
                    end: 10, //滚动过程显示的结束索引
                }
            },
            computed: {
                //显示的数组，用计算属性计算
                showList() {
                    return this.list.slice(this.start, this.end);
                }
            },
            mounted() {
                //构造一个超长列表
                for (let i = 0; i < 1000000; i++) {
                    this.list.push('列表' + i)
                }
                //计算滚动容器高度
                this.$refs.listWrap.style.height = this.itemHeight * this.showNum + 'px';
                //计算总的数据需要的高度，构造滚动条高度
                this.$refs.scrollBar.style.height = this.itemHeight * this.list.length + 'px';
            },
            methods: {
                scrollListener() {
                    //获取滚动高度
                    let scrollTop = this.$refs.listWrap.scrollTop;
                    //开始的数组索引
                    this.start = Math.floor(scrollTop / this.itemHeight);
                    //结束索引
                    this.end = this.start + this.showNum;
                    //绝对定位对相对定位的偏移量
                    this.$refs.list.style.top = this.start * this.itemHeight + 'px';
                }
            }
        })
    </script>
</body>

</html>